"""设备管理路由模块
根据设备模块开发方案要求实现的设备管理接口
"""
from datetime import datetime
from typing import List, Optional

from fastapi import APIRouter, Depends, Path, Query, Body

from app.common.auth import get_current_user, require_device_manage
from app.common.common import DbDep, AuditLogDep, PaginationDep
from app.crud import device_crud as device_crud
from app.crud.address_crud import (
	get_device_address_list, get_device_address_by_id,
	create_device_address, update_device_address, delete_device_address
)
from app.crud.device_crud import get_box_by_id, get_station_list, get_box_list, update_box, delete_box, \
	get_rtu_list, get_rtu_by_id, update_rtu, delete_rtu, get_meter_list, \
	get_meter_by_id, update_meter, delete_meter, get_station_by_id, delete_station, \
	get_station_by_serial_no, get_box_by_serial_no, get_rtu_by_serial_no, get_meter_by_serial_no
from app.schemas.address_schemas import (
	DeviceAddressCreate, DeviceAddressUpdate, DeviceAddressResponse,
	DeviceAddressListRequest, DeviceAddressListResponse
)
from app.schemas.device_schemas import (
	StationCreate, StationUpdate, StationResponse,
	BoxCreate, BoxUpdate, BoxResponse,
	RTUCreate, RTUUpdate, RTUResponse,
	MeterCreate, MeterUpdate, MeterResponse,
	DeviceQuery, DeviceAddressOption, DeviceOperationResult,
	BatchOperationResult, DeviceTreeNode, SerialNoValidationRequest, SerialNoValidationResponse
)
from app.schemas.user_schemas import UserInDB
from app.service.address_service import AddressService
from app.service.device_service import DeviceService
from common.base_enums import DeviceStatus, DeviceType
from common.exceptions import BizException, ErrorCode
from common.logger import create_logger
from common.response import ApiResponse, PaginatedResponse, PaginationParams

logger = create_logger("devices_router")

router = APIRouter(prefix="/devices", tags=["设备管理"])


# ============ 设备序列号验证 ============

@router.post("/validate-serial-no", response_model=ApiResponse[SerialNoValidationResponse],
			 summary="验证设备序列号是否存在")
async def validate_serial_no(
		db: DbDep,
		request: SerialNoValidationRequest,
		_: UserInDB = Depends(get_current_user)
) -> ApiResponse[SerialNoValidationResponse]:
	"""
	验证设备序列号是否已存在

	参数:
	- device_type: 设备类型 (STATION/BOX/RTU/METER)
	- serial_no: 设备序列号
	- filter_status: 是否过滤设备状态（不返回已停用的设备）

	返回:
	- exists: 序列号是否已存在
	- device_id: 设备ID（若存在）
	- device_info: 设备基本信息（若存在）
	"""
	try:
		device_type = request.device_type.upper()

		# 根据设备类型调用相应的查询方法
		if device_type == DeviceType.STATION.value:
			device = await get_station_by_serial_no(db, request.serial_no)
		elif device_type == DeviceType.BOX.value:
			device = await get_box_by_serial_no(db, request.serial_no)
		elif device_type == DeviceType.RTU.value:
			device = await get_rtu_by_serial_no(db, request.serial_no)
		elif device_type == DeviceType.METER.value:
			device = await get_meter_by_serial_no(db, request.serial_no)
		else:
			raise BizException.from_error_code(
				ErrorCode.BAD_REQUEST,
				message=f"不支持的设备类型: {request.device_type}"
			)

		if not device:
			return ApiResponse.success(
				SerialNoValidationResponse(exists=False),
				message="序列号可用"
			)

		# 检查设备状态过滤
		if request.filter_status and hasattr(device, 'status'):
			from common.base_enums import DeviceStatus
			if device.status == DeviceStatus.DECOMMISSIONED.value:
				# 已停用的设备视为不存在（可重用序列号）
				return ApiResponse.success(
					SerialNoValidationResponse(exists=False),
					message="序列号可用（原设备已停用）"
				)

		# 构建设备信息响应
		device_info = SerialNoValidationResponse(
			exists=True,
			device_id=device.id,
			device_type=device_type,
			device_code=getattr(device, 'code', None),
			device_name=getattr(device, 'name', None),
			status=getattr(device, 'status', None)
		)

		return ApiResponse.success(device_info, message="序列号已存在")
	except BizException as e:
		logger.exception("验证设备序列号失败: %s", e)
		raise BizException.from_error_code(
			ErrorCode.INTERNAL_SERVER_ERROR,
			message="验证设备序列号失败"
		)


# ============ 台区管理 ============

@router.get("/stations/list", response_model=ApiResponse[PaginatedResponse[StationResponse]], summary="分页查询台区")
async def list_stations(
		db: DbDep,
		page: int = Query(1, ge=1, description="页码"),
		size: int = Query(20, ge=1, le=100, description="每页大小"),
		keyword: Optional[str] = Query(None, description="关键字搜索"),
		station_id: int = Query(None, description="台区ID"),
		_: UserInDB = Depends(get_current_user)
) -> ApiResponse[PaginatedResponse[StationResponse]]:
	"""
	分页查询台区列表
	"""
	query = DeviceQuery(page=page, size=size, keyword=keyword, status=None, manager_code=None, station_id=station_id)
	total, stations = await device_crud.get_station_list(db, query)

	# 为每个台区添加完整信息，包括位置信息
	from app.service.device_service import DeviceService
	try:
		station_responses = await DeviceService.get_stations_with_location_info(db, stations)
	except Exception:
		# 如果获取完整信息失败，降级返回基本信息
		station_responses = [StationResponse.model_validate(station) for station in stations]

	paginated_data = PaginatedResponse[StationResponse](
		total=total,
		items=station_responses,
		page=page,
		size=size,
		pages=(total + size - 1) // size,
		has_next=page * size < total,
		has_prev=page > 1
	)

	return ApiResponse.success(paginated_data)


@router.post("/stations", response_model=ApiResponse[StationResponse], summary="新建台区")
async def create_station_endpoint(
		db: DbDep,
		_audit: AuditLogDep,
		payload: StationCreate,
		current_user: UserInDB = Depends(require_device_manage),
) -> ApiResponse[StationResponse]:
	"""
	创建新的台区
	支持地址绑定：
	1. 基本信息、address_id和坐标值
	2. 通过AddressBindingService.bind处理地址绑定
	3. 两阶段处理，事务边界清晰
	"""
	try:
		logger.info("开始创建台区，payload=%s", payload.model_dump())

		station_id = await DeviceService.create_station_with_validation(
			db, payload, operator_id=current_user.id
		)

		# 获取创建后的台区信息
		station_with_address = await device_crud.get_station_with_address(db, station_id)
		if not station_with_address:
			raise BizException.from_error_code(ErrorCode.INTERNAL_SERVER_ERROR, message="台区创建后查询失败")

		logger.info("台区创建成功，station_id=%s", station_id)
		return ApiResponse.success(
			StationResponse.from_dict_with_address(station_with_address),
			message="台区创建成功"
		)
	except Exception as e:
		logger.exception("创建台区失败，payload=%s", payload.model_dump())
		raise


@router.put("/stations/{id}", response_model=ApiResponse[StationResponse], summary="更新台区")
async def update_station_endpoint(
		db: DbDep,
		_audit: AuditLogDep,
		id: int = Path(..., description="台区ID"),
		payload: StationUpdate = Body(...),
		_: UserInDB = Depends(require_device_manage),
) -> ApiResponse[StationResponse]:
	"""
	更新台区信息
	支持地址变更：
	- dev_device_address 不 update 原记录，而是新增一条新 address 映射 + 结束旧记录
	- 修改基本信息和address_id（可选），地址信息通过"系统管理"修改
	"""
	try:
		logger.info("开始更新台区，station_id=%s, payload=%s", id, payload.model_dump())

		success = await device_crud.update_station(db, id, payload)
		if not success:
			raise BizException.from_error_code(ErrorCode.NOT_FOUND, message="台区不存在")

		# 获取更新后的台区信息（包含地址）
		station_with_address = await device_crud.get_station_with_address(db, id)
		if not station_with_address:
			raise BizException.from_error_code(ErrorCode.NOT_FOUND, message="台区不存在")

		logger.info("台区更新成功，station_id=%s", id)
		return ApiResponse.success(
			StationResponse.from_dict_with_address(station_with_address),
			message="台区更新成功"
		)
	except Exception:
		logger.exception("更新台区失败，station_id=%s", id)
		raise


@router.delete("/stations/{id}", response_model=ApiResponse[DeviceOperationResult], summary="删除台区")
async def delete_station_endpoint(
		db: DbDep,
		_audit: AuditLogDep,
		id: int = Path(..., description="台区ID"),
		_: UserInDB = Depends(require_device_manage),
) -> ApiResponse[DeviceOperationResult]:
	"""
	删除台区（逻辑删除）
	"""
	success = await device_crud.delete_station(db, id)
	if not success:
		raise BizException.from_error_code(ErrorCode.NOT_FOUND, message="台区不存在")

	result = DeviceOperationResult(
		success=True,
		message="台区删除成功",
		device_id=id
	)
	return ApiResponse.success(result, message="台区删除成功")


@router.get("/stations/{id}", response_model=ApiResponse[StationResponse], summary="获取单个台区详情")
async def get_station(
		db: DbDep,
		id: int = Path(..., description="台区ID"),
		_: UserInDB = Depends(get_current_user),
) -> ApiResponse[StationResponse]:
	"""根据ID获取台区详情（包含地址信息）"""
	station_with_address = await device_crud.get_station_with_address(db, id)
	if not station_with_address:
		raise BizException.from_error_code(ErrorCode.NOT_FOUND, message="台区不存在")

	return ApiResponse.success(StationResponse.from_dict_with_address(station_with_address))


@router.post("/stations/batch", response_model=ApiResponse[BatchOperationResult], summary="Excel 批量导入台区")
async def batch_create_stations(
		db: DbDep,
		payloads: List[StationCreate],
		_: UserInDB = Depends(require_device_manage),
) -> ApiResponse[BatchOperationResult]:
	"""
	批量创建台区
	"""
	created_count = 0
	errors = []

	for i, payload in enumerate(payloads):
		try:
			await DeviceService.create_station_with_validation(db, payload, payload.address_id)
			created_count += 1
		except Exception as e:
			errors.append(f"第{i + 1}个台区创建失败: {str(e)}")

	result = BatchOperationResult(
		total=len(payloads),
		success_count=created_count,
		failed_count=len(errors),
		errors=errors
	)

	if errors:
		return ApiResponse.error(
			message=f"批量创建完成，成功{created_count}个，失败{len(errors)}个",
			data=result
		)
	else:
		return ApiResponse.success(result, message=f"批量创建成功，共创建{created_count}个台区")


@router.get("/stations/{id}/tree", response_model=ApiResponse[DeviceTreeNode], summary="获取台区-电箱-RTU-电表 完整树")
async def get_device_tree(
		db: DbDep,
		_audit: AuditLogDep,
		id: int = Path(..., description="台区ID"),
		_: UserInDB = Depends(get_current_user),
) -> ApiResponse[DeviceTreeNode]:
	"""
	根据台区ID获取设备树结构
	"""
	tree = await DeviceService.get_device_tree(db, id)
	return ApiResponse.success(tree)


@router.get("/users/{userId}/stations", response_model=ApiResponse[PaginatedResponse[StationResponse]],
			summary="查询某用户有权限的台区列表")
async def list_user_stations(
		db: DbDep,
		_audit: AuditLogDep,
		userId: int = Path(..., description="用户ID"),
		query: DeviceQuery = Depends(),
		_: UserInDB = Depends(get_current_user),
) -> ApiResponse[PaginatedResponse[StationResponse]]:
	"""
	查询某用户有权限的台区列表，包含完整的位置信息
	注意：此接口需要根据实际的权限系统实现，这里简化处理返回所有台区
	"""
	try:
		logger.info("查询用户台区列表，userId=%s, query=%s", userId, query.model_dump())
		total, stations = await get_station_list(db, query)

		# 为每个台区添加位置信息
		station_responses = []
		for station in stations:
			try:
				# 获取台区的地址信息
				station_with_address = await device_crud.get_station_with_address(db, station.id)
				if station_with_address:
					station_response = StationResponse.from_dict_with_address(station_with_address)
				else:
					# 如果获取地址信息失败，仍返回基本信息
					station_response = StationResponse.model_validate(station)
					station_response.location_info = []
				station_responses.append(station_response)
			except Exception as e:
				logger.warning("获取台区地址信息失败，station_id=%s, error=%s", station.id, str(e))
				# 即使地址信息获取失败，也要返回基本台区信息
				station_response = StationResponse.model_validate(station)
				station_response.location_info = []
				station_responses.append(station_response)

		paginated_data = PaginatedResponse[StationResponse](
			total=total,
			items=station_responses,
			page=query.page,
			size=query.size,
			pages=(total + query.size - 1) // query.size,
			has_next=query.page * query.size < total,
			has_prev=query.page > 1
		)

		logger.info("成功查询用户台区列表，userId=%s, total=%s", userId, total)
		return ApiResponse.success(paginated_data)
	except Exception:
		logger.exception("查询用户台区列表失败，userId=%s", userId)
		raise


# ============ 电箱管理 ============

@router.get("/boxes/list", response_model=ApiResponse[PaginatedResponse[BoxResponse]], summary="分页查询电箱")
async def list_boxes(
		db: DbDep,
		query: DeviceQuery = Depends(),
		_: UserInDB = Depends(get_current_user)
) -> ApiResponse[PaginatedResponse[BoxResponse]]:
	"""
	分页查询电箱列表，包含完整的位置信息
	"""
	try:
		# 处理空字符串状态值，设置为None表示查询所有状态
		if query.status == "":
			query.status = None

		total, boxes = await get_box_list(db, query)

		# 为每个电箱添加位置信息
		box_responses = await DeviceService.get_boxes_with_location_info(db, boxes)

		paginated_data = PaginatedResponse[BoxResponse](
			total=total,
			items=box_responses,
			page=query.page,
			size=query.size,
			pages=(total + query.size - 1) // query.size,
			has_next=query.page * query.size < total,
			has_prev=query.page > 1
		)

		logger.info("成功查询电箱列表，total=%s", total)
		return ApiResponse.success(paginated_data)
	except BizException:
		logger.exception("分页查询电箱列表失败")
		raise


@router.post("/boxes", response_model=ApiResponse[BoxResponse], summary="新廻电箱")
async def create_box_endpoint(
		db: DbDep,
		_audit: AuditLogDep,
		payload: BoxCreate,
		current_user: UserInDB = Depends(require_device_manage),
) -> ApiResponse[BoxResponse]:
	"""
	创建新的电箱
	"""
	box_id = await DeviceService.create_box_with_validation(
		db, payload, operator_id=current_user.id
	)
	box = await get_box_by_id(db, box_id)
	return ApiResponse.success(BoxResponse.model_validate(box), message="电箱创建成功")


@router.put("/boxes/{id}", response_model=ApiResponse[BoxResponse], summary="更新电箱")
async def update_box_endpoint(
		db: DbDep,
		_audit: AuditLogDep,
		id: int = Path(..., description="电箱ID"),
		payload: BoxUpdate = Body(...),
		current_user: UserInDB = Depends(require_device_manage)
) -> ApiResponse[BoxResponse]:
	"""
	更新电箱信息（支持文件更新）
	"""
	# 1. 获取旧值用于日志记录
	old_box = await get_box_by_id(db, id)
	if not old_box:
		raise BizException.from_error_code(ErrorCode.NOT_FOUND, message="电箱不存在")

	# 2. 执行更新
	success = await DeviceService.update_box_with_file_update(db, id, payload)
	if not success:
		raise BizException.from_error_code(ErrorCode.NOT_FOUND, message="电箱不存在")

	# 3. 验证响应数据
	_box = await get_box_by_id(db, id)
	box_response = BoxResponse.model_validate(_box)

	# 4. 仅在完全成功后记录日志
	from app.service.device_service import _log_device_operation
	await _log_device_operation(
		db=db,
		device_type="BOX",
		device_id=id,
		op_type="UPDATE",
		op_by=current_user.id,
		note=f"更新电箱,设备序列号:{old_box.serial_no or 'N/A'}",
		old_vals=old_box.model_dump(),
		new_vals=payload.model_dump(exclude_unset=True)
	)

	return ApiResponse.success(box_response, message="电箱更新成功")


@router.delete("/boxes/{id}", response_model=ApiResponse[DeviceOperationResult], summary="删除电箱")
async def delete_box_endpoint(
		db: DbDep,
		_audit: AuditLogDep,
		id: int = Path(..., description="电箱ID"),
		current_user: UserInDB = Depends(require_device_manage)
) -> ApiResponse[DeviceOperationResult]:
	"""
	删除电箱（逻辑删除）
	"""
	# 获取设备信息用于日志记录
	old_box = await get_box_by_id(db, id)
	if not old_box:
		raise BizException.from_error_code(ErrorCode.NOT_FOUND, message="电箱不存在")

	# 执行删除
	success = await delete_box(db, id)
	if not success:
		raise BizException.from_error_code(ErrorCode.NOT_FOUND, message="电箱不存在")

	# 记录操作日志
	from app.service.device_service import _log_device_operation
	await _log_device_operation(
		db=db,
		device_type="BOX",
		device_id=id,
		op_type="DELETE",
		op_by=current_user.id,
		note=f"删除电箱,设备序列号:{old_box.serial_no or 'N/A'}",
		old_vals=old_box.model_dump()
	)

	result = DeviceOperationResult(
		success=True,
		message="电箱删除成功",
		device_id=id
	)
	return ApiResponse.success(result, message="电箱删除成功")


@router.get("/boxes/{id}", response_model=ApiResponse[BoxResponse], summary="获取单条电箱详情")
async def get_box(
		db: DbDep,
		id: int = Path(..., description="电箱ID"),
		_: UserInDB = Depends(get_current_user),
) -> ApiResponse[BoxResponse]:
	"""
	根据ID获取电箱详情（包含地址信息和文件列表）
	"""
	from app.service.device_service import DeviceService
	box_complete_info = await DeviceService.get_box_with_complete_info(db, id)
	if not box_complete_info:
		raise BizException.from_error_code(ErrorCode.NOT_FOUND, message="电箱不存在")

	return ApiResponse.success(BoxResponse.from_dict_with_address(box_complete_info))


@router.post("/boxes/batch", response_model=ApiResponse[BatchOperationResult], summary="批量导入电箱")
async def batch_create_boxes(
		db: DbDep,
		payloads: List[BoxCreate],
		_: UserInDB = Depends(require_device_manage),
) -> ApiResponse[BatchOperationResult]:
	"""
	批量创建电箱
	"""
	created_count = 0
	errors = []

	for i, payload in enumerate(payloads):
		try:
			await DeviceService.create_box_with_validation(db, payload)
			created_count += 1
		except Exception as e:
			errors.append(f"第{i + 1}个电箱创建失败: {str(e)}")

	result = BatchOperationResult(
		total=len(payloads),
		success_count=created_count,
		failed_count=len(errors),
		errors=errors
	)

	if errors:
		return ApiResponse.error(
			message=f"批量创建完成，成功{created_count}个，失败{len(errors)}个",
			data=result
		)
	else:
		return ApiResponse.success(result, message=f"批量创建成功，共创建{created_count}个电箱")


@router.get("/users/{userId}/boxes", response_model=ApiResponse[PaginatedResponse[BoxResponse]],
			summary="查询某用户有权限的电箱")
async def list_user_boxes(
		db: DbDep,
		userId: int = Path(..., description="用户ID"),
		query: DeviceQuery = Depends(),
		_: UserInDB = Depends(get_current_user),
) -> ApiResponse[PaginatedResponse[BoxResponse]]:
	"""
	查询某用户有权限的电箱，包含完整的位置信息
	注意：此接口需要根据实际的权限系统实现，这里简化处理返回所有电箱
	"""
	try:
		logger.info("查询用户电箱列表，userId=%s, query=%s", userId, query.model_dump())

		# 处理空字符串状态值，设置为None表示查询所有状态
		if query.status == "":
			query.status = None
		total, boxes = await get_box_list(db, query)

		# 为每个电箱添加位置信息
		box_responses = await DeviceService.get_boxes_with_location_info(db, boxes)

		paginated_data = PaginatedResponse[BoxResponse](
			total=total,
			items=box_responses,
			page=query.page,
			size=query.size,
			pages=(total + query.size - 1) // query.size,
			has_next=query.page * query.size < total,
			has_prev=query.page > 1
		)

		logger.info("成功查询用户电箱列表，userId=%s, total=%s", userId, total)
		return ApiResponse.success(paginated_data)
	except Exception:
		logger.exception("查询用户电箱列表失败，userId=%s", userId)
		raise


# ============ RTU管理 ============

@router.get("/rtus/list", response_model=ApiResponse[PaginatedResponse[RTUResponse]], summary="分页查询RTU")
async def list_rtus(
		db: DbDep,
		query: DeviceQuery = Depends(),
		_: UserInDB = Depends(get_current_user)
) -> ApiResponse[PaginatedResponse[RTUResponse]]:
	"""
	分页查询RTU列表
	"""
	# 处理空字符串状态值，设置为None表示查询所有状态
	if query.status == "":
		query.status = None

	total, rtus = await get_rtu_list(db, query)

	try:
		# 调用新增的方法获取RTU列表的地址信息
		items = await DeviceService.get_rtus_with_location_info(db, rtus)
	except BizException as e:
		# 如果获取位置信息失败，降级返回基本信息
		items = [RTUResponse.model_validate(rtu) for rtu in rtus]

	paginated_data = PaginatedResponse[RTUResponse](
		total=total,
		items=items,
		page=query.page,
		size=query.size,
		pages=(total + query.size - 1) // query.size,
		has_next=query.page * query.size < total,
		has_prev=query.page > 1
	)

	return ApiResponse.success(paginated_data)


@router.post("/rtus", response_model=ApiResponse[RTUResponse], summary="新建RTU")
async def create_rtu_endpoint(
		db: DbDep,
		_audit: AuditLogDep,
		payload: RTUCreate,
		current_user: UserInDB = Depends(require_device_manage),
) -> ApiResponse[RTUResponse]:
	"""
	创建新的RTU
	"""
	rtu_id = await DeviceService.create_rtu_with_validation(
		db, payload, operator_id=current_user.id
	)
	rtu = await get_rtu_by_id(db, rtu_id)
	return ApiResponse.success(RTUResponse.model_validate(rtu), message="RTU创建成功")


@router.put("/rtus/{id}", response_model=ApiResponse[RTUResponse], summary="更新RTU")
async def update_rtu_endpoint(
		db: DbDep,
		_audit: AuditLogDep,
		id: int = Path(..., description="RTU ID"),
		payload: RTUUpdate = Body(...),
		current_user: UserInDB = Depends(require_device_manage)
) -> ApiResponse[RTUResponse]:
	"""
	更新RTU信息（支持文件更新）
	"""
	# 1. 获取旧值用于日志记录
	old_rtu = await get_rtu_by_id(db, id)
	if not old_rtu:
		raise BizException.from_error_code(ErrorCode.NOT_FOUND, message="RTU不存在")

	# 2. 执行更新
	success = await DeviceService.update_rtu_with_file_update(db, id, payload)
	if not success:
		raise BizException.from_error_code(ErrorCode.NOT_FOUND, message="RTU不存在")

	# 3. 验证响应数据
	_rtu = await get_rtu_by_id(db, id)
	rtu_response = RTUResponse.model_validate(_rtu)

	# 4. 仅在完全成功后记录日志
	from app.service.device_service import _log_device_operation
	await _log_device_operation(
		db=db,
		device_type="RTU",
		device_id=id,
		op_type="UPDATE",
		op_by=current_user.id,
		note=f"更新RTU,设备序列号:{old_rtu.serial_no or 'N/A'}",
		old_vals=old_rtu.model_dump(),
		new_vals=payload.model_dump(exclude_unset=True)
	)

	return ApiResponse.success(rtu_response, message="RTU更新成功")


@router.delete("/rtus/{id}", response_model=ApiResponse[DeviceOperationResult], summary="删除RTU")
async def delete_rtu_endpoint(
		db: DbDep,
		_audit: AuditLogDep,
		id: int = Path(..., description="RTU ID"),
		current_user: UserInDB = Depends(require_device_manage),
) -> ApiResponse[DeviceOperationResult]:
	"""
	删除RTU（逻辑删除）
	"""
	# 获取设备信息用于日志记录
	old_rtu = await get_rtu_by_id(db, id)
	if not old_rtu:
		raise BizException.from_error_code(ErrorCode.NOT_FOUND, message="RTU不存在")

	# 执行删除
	success = await delete_rtu(db, id)
	if not success:
		raise BizException.from_error_code(ErrorCode.NOT_FOUND, message="RTU不存在")

	# 记录操作日志
	from app.service.device_service import _log_device_operation
	await _log_device_operation(
		db=db,
		device_type="RTU",
		device_id=id,
		op_type="DELETE",
		op_by=current_user.id,
		note=f"删除RTU,设备序列号:{old_rtu.serial_no or 'N/A'}",
		old_vals=old_rtu.model_dump()
	)

	result = DeviceOperationResult(
		success=True,
		message="RTU删除成功",
		device_id=id
	)
	return ApiResponse.success(result, message="RTU删除成功")


@router.get("/rtus/{id}", response_model=ApiResponse[RTUResponse], summary="获取单条RTU详情")
async def get_rtu(
		db: DbDep,
		id: int = Path(..., description="RTU ID"),
		_: UserInDB = Depends(get_current_user),
) -> ApiResponse[RTUResponse]:
	"""
	根据ID获取RTU详情（包含地址信息和文件列表）
	"""
	from app.service.device_service import DeviceService
	rtu_complete_info = await DeviceService.get_rtu_with_complete_info(db, id)
	if not rtu_complete_info:
		raise BizException.from_error_code(ErrorCode.NOT_FOUND, message="RTU不存在")

	return ApiResponse.success(RTUResponse.from_dict_with_address(rtu_complete_info))


@router.post("/rtus/batch", response_model=ApiResponse[BatchOperationResult], summary="批量导入RTU")
async def batch_create_rtus(
		db: DbDep,
		_audit: AuditLogDep,
		payloads: List[RTUCreate],
		_: UserInDB = Depends(require_device_manage)
) -> ApiResponse[BatchOperationResult]:
	"""
	批量创建RTU
	"""
	created_count = 0
	errors = []

	for i, payload in enumerate(payloads):
		try:
			await DeviceService.create_rtu_with_validation(db, payload)
			created_count += 1
		except Exception as e:
			errors.append(f"第{i + 1}个RTU创建失败: {str(e)}")

	result = BatchOperationResult(
		total=len(payloads),
		success_count=created_count,
		failed_count=len(errors),
		errors=errors
	)

	if errors:
		return ApiResponse.error(
			message=f"批量创建完成，成功{created_count}个，失败{len(errors)}个",
			data=result
		)
	else:
		return ApiResponse.success(result, message=f"批量创建成功，共创建{created_count}个RTU")


@router.get("/users/{userId}/rtus", response_model=ApiResponse[PaginatedResponse[RTUResponse]],
			summary="查询某用户有权限的RTU")
async def list_user_rtus(
		db: DbDep,
		query: DeviceQuery = Depends(),
		_: UserInDB = Depends(get_current_user),
) -> ApiResponse[PaginatedResponse[RTUResponse]]:
	"""
	查询某用户有权限的RTU
	说明：按开发规范使用 DeviceQuery 统一接收查询参数（page、size、station_id 等）。
	"""
	# 处理空字符串状态值，设置为None表示查询所有状态（与通用列表接口保持一致）
	if query.status == "":
		query.status = None

	total, rtus = await get_rtu_list(db, query)

	# 为每个RTU添加位置信息
	from app.service.device_service import DeviceService
	try:
		items = await DeviceService.get_rtus_with_location_info(db, rtus)
	except Exception:
		# 如果获取位置信息失败，降级返回基本信息
		items = [RTUResponse.model_validate(rtu) for rtu in rtus]

	paginated_data = PaginatedResponse[RTUResponse](
		total=total,
		items=items,
		page=query.page,
		size=query.size,
		pages=(total + query.size - 1) // query.size,
		has_next=query.page * query.size < total,
		has_prev=query.page > 1
	)

	return ApiResponse.success(paginated_data)


# ============ 电表管理 ============

@router.get("/meters/list", response_model=ApiResponse[PaginatedResponse[MeterResponse]], summary="分页查询电表")
async def list_meters(
		db: DbDep,
		query: DeviceQuery = Depends(),
		_: UserInDB = Depends(get_current_user),
) -> ApiResponse[PaginatedResponse[MeterResponse]]:
	"""
	分页查询电表列表
	"""
	# 处理空字符串状态值，设置为None表示查询所有状态
	if query.status == "":
		query.status = None

	total, meters = await get_meter_list(db, query)

	# 为每个电表添加完整信息，包括位置信息和关联设备编号
	from app.service.device_service import DeviceService
	try:
		meter_responses = await DeviceService.get_meters_with_complete_info(db, meters)
	except Exception:
		# 如果获取完整信息失败，降级返回基本信息
		meter_responses = [MeterResponse.model_validate(meter) for meter in meters]

	paginated_data = PaginatedResponse[MeterResponse](
		total=total,
		items=meter_responses,
		page=query.page,
		size=query.size,
		pages=(total + query.size - 1) // query.size,
		has_next=query.page * query.size < total,
		has_prev=query.page > 1
	)

	return ApiResponse.success(paginated_data)


@router.post("/meters", response_model=ApiResponse[MeterResponse], summary="新建电表")
async def create_meter_endpoint(
		db: DbDep,
		_audit: AuditLogDep,
		payload: MeterCreate,
		current_user: UserInDB = Depends(require_device_manage),
) -> ApiResponse[MeterResponse]:
	"""
	创建新的电表
	"""
	meter_id = await DeviceService.create_meter_with_validation(
		db, payload, operator_id=current_user.id
	)
	meter = await get_meter_by_id(db, meter_id)
	return ApiResponse.success(MeterResponse.model_validate(meter), message="电表创建成功")


@router.put("/meters/{id}", response_model=ApiResponse[MeterResponse], summary="更新电表")
async def update_meter_endpoint(
		db: DbDep,
		_audit: AuditLogDep,
		id: int = Path(..., description="电表ID"),
		payload: MeterUpdate = Body(...),
		current_user: UserInDB = Depends(require_device_manage),
) -> ApiResponse[MeterResponse]:
	"""
	更新电表信息（支持文件更新）
	"""
	# 1. 获取旧值用于日志记录
	old_meter = await get_meter_by_id(db, id)
	if not old_meter:
		raise BizException.from_error_code(ErrorCode.NOT_FOUND, message="电表不存在")

	# 2. 执行更新
	success = await DeviceService.update_meter_with_file_update(db, id, payload)
	if not success:
		raise BizException.from_error_code(ErrorCode.NOT_FOUND, message="电表不存在")

	# 3. 验证响应数据
	_meter = await get_meter_by_id(db, id)
	meter_response = MeterResponse.model_validate(_meter)

	# 4. 仅在完全成功后记录日志
	from app.service.device_service import _log_device_operation
	await _log_device_operation(
		db=db,
		device_type="METER",
		device_id=id,
		op_type="UPDATE",
		op_by=current_user.id,
		note=f"更新电表,设备序列号:{old_meter.serial_no or 'N/A'}",
		old_vals=old_meter.model_dump(),
		new_vals=payload.model_dump(exclude_unset=True)
	)

	return ApiResponse.success(meter_response, message="电表更新成功")


@router.delete("/meters/{id}", response_model=ApiResponse[DeviceOperationResult], summary="删除电表")
async def delete_meter_endpoint(
		db: DbDep,
		_audit: AuditLogDep,
		id: int = Path(..., description="电表ID"),
		current_user: UserInDB = Depends(require_device_manage),
) -> ApiResponse[DeviceOperationResult]:
	"""
	删除电表（逻辑删除）
	"""
	# 获取设备信息用于日志记录
	old_meter = await get_meter_by_id(db, id)
	if not old_meter:
		raise BizException.from_error_code(ErrorCode.NOT_FOUND, message="电表不存在")

	# 执行删除
	success = await delete_meter(db, id)
	if not success:
		raise BizException.from_error_code(ErrorCode.NOT_FOUND, message="电表不存在")

	# 记录操作日志
	from app.service.device_service import _log_device_operation
	await _log_device_operation(
		db=db,
		device_type="METER",
		device_id=id,
		op_type="DELETE",
		op_by=current_user.id,
		note=f"删除电表,设备序列号:{old_meter.serial_no or 'N/A'}",
		old_vals=old_meter.model_dump()
	)

	result = DeviceOperationResult(
		success=True,
		message="电表删除成功",
		device_id=id
	)
	return ApiResponse.success(result, message="电表删除成功")


@router.get("/meters/{id}", response_model=ApiResponse[MeterResponse], summary="获取单条电表详情")
async def get_meter(
		db: DbDep,
		id: int = Path(..., description="电表ID"),
		_: UserInDB = Depends(get_current_user),
) -> ApiResponse[MeterResponse]:
	"""
	根据ID获取电表详情（包含地址信息和关联设备编号）
	"""
	try:
		logger.info("获取电表详情，meter_id=%s", id)

		meter_complete_info = await DeviceService.get_meter_with_complete_info(db, id)
		if not meter_complete_info:
			raise BizException.from_error_code(ErrorCode.NOT_FOUND, message="电表地址信息不存在")

		meter_response = MeterResponse.from_dict_with_address(meter_complete_info)
		logger.info("成功获取电表详情，meter_id=%s", id)
		return ApiResponse.success(meter_response)
	except Exception:
		logger.exception("获取电表详情失败，meter_id=%s", id)
		raise


@router.post("/meters/batch", response_model=ApiResponse[BatchOperationResult], summary="批量导入电表")
async def batch_create_meters(
		db: DbDep,
		_audit: AuditLogDep,
		payloads: List[MeterCreate],
		_: UserInDB = Depends(require_device_manage),
) -> ApiResponse[BatchOperationResult]:
	"""
	批量创建电表
	"""
	created_count = 0
	errors = []

	for i, payload in enumerate(payloads):
		try:
			await DeviceService.create_meter_with_validation(db, payload)
			created_count += 1
		except Exception as e:
			errors.append(f"第{i + 1}个电表创建失败: {str(e)}")

	result = BatchOperationResult(
		total=len(payloads),
		success_count=created_count,
		failed_count=len(errors),
		errors=errors
	)

	if errors:
		return ApiResponse.error(
			message=f"批量创建完成，成功{created_count}个，失败{len(errors)}个",
			data=result
		)
	else:
		return ApiResponse.success(result, message=f"批量创建成功，共创建{created_count}个电表")


@router.get("/users/{userId}/meters", response_model=ApiResponse[PaginatedResponse[MeterResponse]],
			summary="查询某用户有权限的电表")
async def list_user_meters(
		db: DbDep,
		userId: int = Path(..., description="用户ID"),
		query: DeviceQuery = Depends(),
		_: UserInDB = Depends(get_current_user),
) -> ApiResponse[PaginatedResponse[MeterResponse]]:
	"""
	查询某用户有权限的电表，包含完整的位置信息和关联设备编号
	注意：此接口需要根据实际的权限系统实现，这里简化处理返回所有电表
	"""
	try:
		logger.info("查询用户电表列表，userId=%s, query=%s", userId, query.model_dump())

		# 处理空字符串状态值，设置为None表示查询所有状态
		if query.status == "":
			query.status = None
		total, meters = await get_meter_list(db, query)

		# 为每个电表添加完整信息，包括位置信息和关联设备编号
		meter_responses = await DeviceService.get_meters_with_complete_info(db, meters)

		paginated_data = PaginatedResponse[MeterResponse](
			total=total,
			items=meter_responses,
			page=query.page,
			size=query.size,
			pages=(total + query.size - 1) // query.size,
			has_next=query.page * query.size < total,
			has_prev=query.page > 1
		)

		logger.info("成功查询用户电表列表，userId=%s, total=%s", userId, total)
		return ApiResponse.success(paginated_data)
	except Exception:
		logger.exception("查询用户电表列表失败，userId=%s", userId)
		raise


# ============ 设备替换/报废 ============

@router.post("/meters/{id}/replace", response_model=ApiResponse[DeviceOperationResult], summary="电表替换")
async def replace_meter(
		db: DbDep,
		_audit: AuditLogDep,
		id: int = Path(..., description="电表ID"),
		new_meter_payload: MeterCreate = Body(..., embed=True),
		current_user: UserInDB = Depends(require_device_manage),
) -> ApiResponse[DeviceOperationResult]:
	"""
	电表替换流程:
	1. 创建新电表(继承box_id和rtu_id)
	2. 如果是三相表,迁移层级关系(parent_meter_id指向新表)
	3. 将旧电表状态变更为已停用
	4. 记录设备事件
	"""
	# 检查旧电表是否存在
	old_meter = await get_meter_by_id(db, id)
	if not old_meter:
		raise BizException.from_error_code(ErrorCode.NOT_FOUND, message="旧电表不存在")

	# 检查旧电表状态是否允许替换
	if old_meter.status == DeviceStatus.DECOMMISSIONED:
		raise BizException.from_error_code(ErrorCode.BAD_REQUEST, message="已停用的电表不能替换")

	async with db.transaction():
		# 继承box_id和rtu_id
		if not new_meter_payload.box_id:
			new_meter_payload.box_id = old_meter.box_id
		if not new_meter_payload.rtu_id:
			new_meter_payload.rtu_id = old_meter.rtu_id

		# 创建新电表
		new_meter_id = await DeviceService.create_meter_with_validation(db, new_meter_payload)
		new_meter = await get_meter_by_id(db, new_meter_id)

		# 如果是三相表,迁移层级关系
		migrated_hierarchy_count = 0
		if old_meter.meter_type == 'THREE_PHASE':
			update_hierarchy_sql = """
				UPDATE dev_meter_hierarchy
				SET parent_meter_id = %s
				WHERE parent_meter_id = %s
			"""
			migrated_hierarchy_count = db.update(update_hierarchy_sql, (new_meter_id, id))
			logger.info(f"电表替换: 三相表({id})迁移{migrated_hierarchy_count}个层级关系到新表({new_meter_id})")

		# 将旧电表状态变更为已停用并标记为逻辑删除
		update_data = MeterUpdate(status=DeviceStatus.DECOMMISSIONED)
		success = await update_meter(db, id, update_data)
		if not success:
			raise BizException.from_error_code(ErrorCode.INTERNAL_SERVER_ERROR, message="旧电表停用失败")

		# 将旧电表标记为逻辑删除（不再使用）
		delete_sql = "UPDATE dev_meter SET deleted = 1, updated_at = NOW() WHERE id = %s"
		db.update(delete_sql, (id,))
		logger.info(f"电表替换: 旧电表({id})已标记为逻辑删除")

		# 记录设备替换事件
		event_data = {
			"target_type": "METER",
			"target_id": id,
			"event_type": "REPLACED",
			"event_time": datetime.now(),
			"operator_id": current_user.id,
			"related_device_id": new_meter_id,
			"reason": "设备替换" + (f",迁移{migrated_hierarchy_count}个单相表" if migrated_hierarchy_count > 0 else ""),
			"old_value": old_meter.serial_no,
			"new_value": new_meter.serial_no
		}

		from app.crud.device_event_crud import create_device_event
		await create_device_event(db, event_data)

	message = f"电表替换成功" + (f",已迁移{migrated_hierarchy_count}个单相表" if migrated_hierarchy_count > 0 else "")
	result = DeviceOperationResult(
		success=True,
		message=message,
		old_device_id=id,
		new_device_id=new_meter_id
	)
	return ApiResponse.success(result, message=message)


@router.post("/rtus/{id}/replace", response_model=ApiResponse[DeviceOperationResult], summary="RTU替换")
async def replace_rtu(
		db: DbDep,
		_audit: AuditLogDep,
		id: int = Path(..., description="RTU ID"),
		new_rtu_payload: RTUCreate = Body(..., embed=True),
		current_user: UserInDB = Depends(require_device_manage)
) -> ApiResponse[DeviceOperationResult]:
	"""
	RTU替换流程
	1. 创建新RTU
	2. 将旧RTU下的所有电表迁移到新RTU
	3. 将旧RTU状态变更为已停用
	4. 记录设备事件
	注意:整个流程在一个事务中完成,保证数据一致性
	"""
	# 调用Service层
	result_data = await DeviceService.replace_rtu(db, id, new_rtu_payload, current_user.id)
	
	result = DeviceOperationResult(
		success=True,
		message=f"RTU替换成功,已迁移{result_data['affected_meter_count']}个电表",
		old_device_id=id,
		new_device_id=result_data['new_rtu_id']
	)
	return ApiResponse.success(result, message=f"RTU替换成功,已迁移{result_data['affected_meter_count']}个电表")


@router.post("/boxes/{id}/replace", response_model=ApiResponse[DeviceOperationResult], summary="电箱替换")
async def replace_box(
		db: DbDep,
		_audit: AuditLogDep,
		id: int = Path(..., description="电箱ID"),
		new_box_payload: BoxCreate = Body(..., embed=True),
		current_user: UserInDB = Depends(require_device_manage)
) -> ApiResponse[DeviceOperationResult]:
	"""
	电箱替换流程
	1. 创建新电箱
	2. 将旧电箱状态变更为已停用
	3. 记录设备事件
	"""
	# 检查旧电箱是否存在
	old_box = await get_box_by_id(db, id)
	if not old_box:
		raise BizException.from_error_code(ErrorCode.NOT_FOUND, message="旧电箱不存在")

	# 检查旧电箱状态是否允许替换
	if old_box.status == DeviceStatus.DECOMMISSIONED:
		raise BizException.from_error_code(ErrorCode.BAD_REQUEST, message="已停用的电箱不能替换")

	# 创建新电箱
	new_box_id = await DeviceService.create_box_with_validation(db, new_box_payload)
	new_box = await get_box_by_id(db, new_box_id)

	# 将旧电箱状态变更为已停用
	update_data = BoxUpdate(status=DeviceStatus.DECOMMISSIONED)
	success = await update_box(db, id, update_data)
	if not success:
		raise BizException.from_error_code(ErrorCode.INTERNAL_SERVER_ERROR, message="旧电箱停用失败")

	# 将旧电箱标记为逻辑删除（不再使用）
	delete_sql = "UPDATE dev_box SET deleted = 1, updated_at = NOW() WHERE id = %s"
	db.update(delete_sql, (id,))
	logger.info(f"电箱替换: 旧电箱({id})已标记为逻辑删除")

	# 记录设备替换事件
	event_data = {
		"target_type": "BOX",
		"target_id": id,
		"event_type": "REPLACED",
		"event_time": datetime.now(),
		"operator_id": current_user.id,
		"related_device_id": new_box_id,
		"reason": "设备替换",
		"old_value": old_box.code,
		"new_value": new_box.code
	}

	from app.crud.device_event_crud import create_device_event
	await create_device_event(db, event_data)

	result = DeviceOperationResult(
		success=True,
		message="电箱替换成功",
		old_device_id=id,
		new_device_id=new_box_id
	)
	return ApiResponse.success(result, message="电箱替换成功")


@router.post("/stations/{id}/replace", response_model=ApiResponse[DeviceOperationResult], summary="台区替换")
async def replace_station(
		db: DbDep,
		_audit: AuditLogDep,
		id: int = Path(..., description="台区ID"),
		new_station_payload: StationCreate = Body(..., embed=True),
		current_user: UserInDB = Depends(require_device_manage)
) -> ApiResponse[DeviceOperationResult]:
	"""
	台区替换流程
	1. 创建新台区
	2. 将旧台区状态变更为已停用（逻辑删除）
	3. 记录设备事件
	"""
	# 检查旧台区是否存在
	old_station = await get_station_by_id(db, id)
	if not old_station:
		raise BizException.from_error_code(ErrorCode.NOT_FOUND, message="旧台区不存在")

	# 将旧台区状态变更为已停用（逻辑删除）
	success = await delete_station(db, id)  # 使用逻辑删除实现报废
	if not success:
		raise BizException.from_error_code(ErrorCode.INTERNAL_SERVER_ERROR, message="旧台区停用失败")

	# 创建新台区
	new_station_id = await DeviceService.create_station_with_validation(db, new_station_payload)
	new_station = await get_station_by_id(db, new_station_id)

	# 记录设备替换事件
	event_data = {
		"target_type": "STATION",
		"target_id": id,
		"event_type": "REPLACED",
		"event_time": datetime.now(),
		"operator_id": current_user.id,
		"related_device_id": new_station_id,
		"reason": "台区替换",
		"old_value": old_station.code,
		"new_value": new_station.code
	}

	from app.crud.device_event_crud import create_device_event
	await create_device_event(db, event_data)

	result = DeviceOperationResult(
		success=True,
		message="台区替换成功",
		old_device_id=id,
		new_device_id=new_station_id
	)
	return ApiResponse.success(result, message="台区替换成功")


# ============ 设备报废 ============

@router.post("/meters/{id}/decommission", response_model=ApiResponse[DeviceOperationResult], summary="电表报废")
async def decommission_meter(
		db: DbDep,
		_audit: AuditLogDep,
		id: int = Path(..., description="电表ID"),
		reason: Optional[str] = Query(None, description="报废原因"),
		current_user: UserInDB = Depends(require_device_manage)
) -> ApiResponse[DeviceOperationResult]:
	"""
	电表报废流程:
	1. 如果是三相表,删除dev_meter_hierarchy中的层级关系
	2. 将电表状态变更为已停用
	3. 记录设备事件
	"""
	# 检查电表是否存在
	meter = await get_meter_by_id(db, id)
	if not meter:
		raise BizException.from_error_code(ErrorCode.NOT_FOUND, message="电表不存在")

	async with db.transaction():
		# 如果是三相表,删除层级关系
		deleted_hierarchy_count = 0
		if meter.meter_type == 'THREE_PHASE':
			delete_hierarchy_sql = "DELETE FROM dev_meter_hierarchy WHERE parent_meter_id = %s"
			deleted_hierarchy_count = db.update(delete_hierarchy_sql, (id,))
			logger.info(f"电表报废: 三相表({id})删除了{deleted_hierarchy_count}个层级关系")
		else:
			# 如果是单相表,也删除其作为子表的关系
			delete_hierarchy_sql = "DELETE FROM dev_meter_hierarchy WHERE child_meter_id = %s"
			deleted_hierarchy_count = db.update(delete_hierarchy_sql, (id,))
			if deleted_hierarchy_count > 0:
				logger.info(f"电表报废: 单相表({id})删除了层级关系")

		# 更新状态为已停用
		update_data = MeterUpdate(status=DeviceStatus.DECOMMISSIONED)
		success = await update_meter(db, id, update_data)
		if not success:
			raise BizException.from_error_code(ErrorCode.INTERNAL_SERVER_ERROR, message="电表报废失败")

		# 将电表标记为逻辑删除（不再使用）
		delete_sql = "UPDATE dev_meter SET deleted = 1, updated_at = NOW() WHERE id = %s"
		db.update(delete_sql, (id,))
		logger.info(f"电表报废: 电表({id})已标记为逻辑删除")

		# 记录设备事件
		event_data = {
			"target_type": "METER",
			"target_id": id,
			"event_type": "DECOMMISSIONED",
			"event_time": datetime.now(),
			"operator_id": current_user.id,
			"reason": reason or "正常报废"
		}

		from app.crud.device_event_crud import create_device_event
		await create_device_event(db, event_data)

	message = f"电表报废成功" + (f",已删除{deleted_hierarchy_count}个层级关系" if deleted_hierarchy_count > 0 else "")
	result = DeviceOperationResult(
		success=True,
		message=message,
		device_id=id
	)
	return ApiResponse.success(result, message=message)


@router.post("/rtus/{id}/decommission", response_model=ApiResponse[DeviceOperationResult], summary="RTU报废")
async def decommission_rtu(
		db: DbDep,
		_audit: AuditLogDep,
		id: int = Path(..., description="RTU ID"),
		reason: Optional[str] = Query(None, description="报废原因"),
		current_user: UserInDB = Depends(require_device_manage)
) -> ApiResponse[DeviceOperationResult]:
	"""
	RTU报废流程:
	1. 解绑关联的电表(rtu_id置空NULL)
	2. 将RTU状态变更为已停用
	3. 记录设备事件
	"""
	# 调用Service层
	unbind_count = await DeviceService.decommission_rtu(db, id, current_user.id, reason)
	
	result = DeviceOperationResult(
		success=True,
		message=f"RTU报废成功,已解绑{unbind_count}个电表",
		device_id=id
	)
	return ApiResponse.success(result, message=f"RTU报废成功,已解绑{unbind_count}个电表")


@router.post("/boxes/{id}/decommission", response_model=ApiResponse[DeviceOperationResult], summary="电箱报废")
async def decommission_box(
		db: DbDep,
		_audit: AuditLogDep,
		id: int = Path(..., description="电箱ID"),
		reason: Optional[str] = Query(None, description="报废原因"),
		current_user: UserInDB = Depends(require_device_manage)
) -> ApiResponse[DeviceOperationResult]:
	"""
	将电箱状态变更为已停用/报废
	"""
	# 检查电箱是否存在
	box = await get_box_by_id(db, id)
	if not box:
		raise BizException.from_error_code(ErrorCode.NOT_FOUND, message="电箱不存在")

	# 更新状态为已停用
	update_data = BoxUpdate(status=DeviceStatus.DECOMMISSIONED)
	success = await update_box(db, id, update_data)
	if not success:
		raise BizException.from_error_code(ErrorCode.INTERNAL_SERVER_ERROR, message="电箱报废失败")

	# 将电箱标记为逻辑删除（不再使用）
	delete_sql = "UPDATE dev_box SET deleted = 1, updated_at = NOW() WHERE id = %s"
	db.update(delete_sql, (id,))
	logger.info(f"电箱报废: 电箱({id})已标记为逻辑删除")

	# 记录设备事件
	event_data = {
		"target_type": "BOX",
		"target_id": id,
		"event_type": "DECOMMISSIONED",
		"event_time": datetime.now(),
		"operator_id": current_user.id,
		"reason": reason or "正常报废"
	}

	from app.crud.device_event_crud import create_device_event
	await create_device_event(db, event_data)

	result = DeviceOperationResult(
		success=True,
		message="电箱报废成功",
		device_id=id
	)
	return ApiResponse.success(result, message="电箱报废成功")


@router.post("/stations/{id}/decommission", response_model=ApiResponse[DeviceOperationResult], summary="台区报废")
async def decommission_station(
		db: DbDep,
		_audit: AuditLogDep,
		id: int = Path(..., description="台区ID"),
		reason: Optional[str] = Query(None, description="报废原因"),
		current_user: UserInDB = Depends(require_device_manage)
) -> ApiResponse[DeviceOperationResult]:
	"""
	将台区状态变更为已停用/报废
	"""
	# 检查台区是否存在
	station = await get_station_by_id(db, id)
	if not station:
		raise BizException.from_error_code(ErrorCode.NOT_FOUND, message="台区不存在")

	# 更新状态为已停用（逻辑删除）
	success = await delete_station(db, id)  # 使用逻辑删除实现报废
	if not success:
		raise BizException.from_error_code(ErrorCode.INTERNAL_SERVER_ERROR, message="台区报废失败")

	# 记录设备事件
	event_data = {
		"target_type": "STATION",
		"target_id": id,
		"event_type": "DECOMMISSIONED",
		"event_time": datetime.now(),
		"operator_id": current_user.id,
		"reason": reason or "正常报废"
	}

	from app.crud.device_event_crud import create_device_event
	await create_device_event(db, event_data)

	result = DeviceOperationResult(
		success=True,
		message="台区报废成功",
		device_id=id
	)
	return ApiResponse.success(result, message="台区报废成功")


@router.get("/boxes/{box_id}/tree", response_model=ApiResponse[DeviceTreeNode], summary="获取RTU-电表 完整树")
async def get_box_rtu_meter_tree(
		db: DbDep,
		box_id: int = Path(..., description="电箱ID"),
		_: UserInDB = Depends(get_current_user)
) -> ApiResponse[DeviceTreeNode]:
	"""
	根据电箱ID获取RTU-电表完整树
	"""
	try:
		device_tree = await DeviceService.get_rtu_meter_tree(db, box_id)
		return ApiResponse.success(device_tree)
	except BizException:
		raise
	except Exception as e:
		logger.exception("获取RTU-电表树失败，box_id=%s", box_id)
		raise BizException.from_error_code(ErrorCode.INTERNAL_SERVER_ERROR, message="获取RTU-电表树失败") from e


# ============ 地址绑定相关接口 ============

@router.get("/boxes/addresses/{station_id}", response_model=ApiResponse[List[DeviceAddressOption]],
			summary="获取电箱可选地址列表")
async def get_box_addresses(
		db: DbDep,
		station_id: int = Path(..., description="台区ID"),
		query: PaginationParams = Depends(),
		_: UserInDB = Depends(get_current_user),
) -> ApiResponse[PaginatedResponse[DeviceAddressOption]]:
	"""
	获取电箱可选地址列表——根据台区主地址的区县码分页查询下级地址
	"""
	try:
		total, rows = await AddressService.get_available_addresses_paged(db, station_id, query)
		pages = (total + query.size - 1) // query.size
		paginated = PaginatedResponse[DeviceAddressOption](
			total=total,
			items=[DeviceAddressOption(**r) for r in rows],
			page=query.page,
			size=query.size,
			pages=pages,
			has_next=query.page * query.size < total,
			has_prev=query.page > 1,
		)
		return ApiResponse.success(data=paginated)
	except BizException:
		raise
	except Exception as e:
		logger.exception("获取电表可选地址列表失败，station_id=%s", station_id)
		raise BizException.from_error_code(ErrorCode.INTERNAL_SERVER_ERROR, message="获取可选地址列表失败") from e


@router.get("/rtus/addresses/{station_id}", response_model=ApiResponse[List[DeviceAddressOption]],
			summary="获取RTU可选地址列表")
async def get_rtu_addresses(
		db: DbDep,
		station_id: int = Path(..., description="台区ID"),
		query: PaginationParams = Depends(),
		_: UserInDB = Depends(get_current_user),
) -> ApiResponse[PaginatedResponse[DeviceAddressOption]]:
	"""
	获取RTU可选地址列表——根据台区主地址的区县码分页查询下级地址
	"""
	try:
		total, rows = await AddressService.get_available_addresses_paged(db, station_id, query)
		pages = (total + query.size - 1) // query.size
		paginated = PaginatedResponse[DeviceAddressOption](
			total=total,
			items=[DeviceAddressOption(**r) for r in rows],
			page=query.page,
			size=query.size,
			pages=pages,
			has_next=query.page * query.size < total,
			has_prev=query.page > 1,
		)
		return ApiResponse.success(data=paginated)
	except BizException:
		raise
	except Exception as e:
		logger.exception("获取RTU可选地址列表失败，station_id=%s", station_id)
		raise BizException.from_error_code(ErrorCode.INTERNAL_SERVER_ERROR, message="获取可选地址列表失败") from e


@router.get("/meters/addresses/{station_id}", response_model=ApiResponse[List[DeviceAddressOption]],
			summary="获取电表可选地址列表")
async def get_meter_addresses(
		db: DbDep,
		station_id: int = Path(..., description="台区ID"),
		query: PaginationParams = Depends(),
		_: UserInDB = Depends(get_current_user),
) -> ApiResponse[PaginatedResponse[DeviceAddressOption]]:
	"""
		获取电表可选地址列表——根据台区主地址的区县码分页查询下级地址
	"""
	try:
		total, rows = await AddressService.get_available_addresses_paged(db, station_id, query)
		pages = (total + query.size - 1) // query.size
		paginated = PaginatedResponse[DeviceAddressOption](
			total=total,
			items=[DeviceAddressOption(**r) for r in rows],
			page=query.page,
			size=query.size,
			pages=pages,
			has_next=query.page * query.size < total,
			has_prev=query.page > 1,
		)
		return ApiResponse.success(data=paginated)
	except BizException:
		raise
	except Exception as e:
		logger.exception("获取电表可选地址列表失败，station_id=%s", station_id)
		raise BizException.from_error_code(ErrorCode.INTERNAL_SERVER_ERROR, message="获取可选地址列表失败") from e


# ============ 设备地址管理 ============

@router.get("/addresses", response_model=ApiResponse[DeviceAddressListResponse], summary="获取设备地址关联列表")
async def list_device_addresses(
		db: DbDep,
		_audit: AuditLogDep,
		page: PaginationDep,
		query: DeviceAddressListRequest = Depends(),
		_: UserInDB = Depends(get_current_user)
) -> ApiResponse[DeviceAddressListResponse]:
	"""获取设备地址关联列表"""
	try:
		total, items = await get_device_address_list(db, query, page.page, page.size)

		device_address_responses = [DeviceAddressResponse.model_validate(item) for item in items]
		result = DeviceAddressListResponse(
			total=total,
			items=device_address_responses
		)

		return ApiResponse.success(result, "设备地址关联列表获取成功")
	except Exception as e:
		return ApiResponse.error(f"获取设备地址关联列表失败: {str(e)}", code=500)


@router.post("/addresses", response_model=ApiResponse[DeviceAddressResponse], summary="创建设备地址")
async def create_device_address_endpoint(
		db: DbDep,
		_audit: AuditLogDep,
		payload: DeviceAddressCreate,
		_: UserInDB = Depends(require_device_manage)
) -> ApiResponse[DeviceAddressResponse]:
	"""创建设备地址关联"""
	try:
		device_address_id = await create_device_address(db, payload)
		device_address = await get_device_address_by_id(db, device_address_id)

		return ApiResponse.success(DeviceAddressResponse.model_validate(device_address), "设备地址创建成功")
	except Exception as e:
		return ApiResponse.error(f"创建设备地址关联失败: {str(e)}", code=500)


@router.put("/addresses/{id}", response_model=ApiResponse[DeviceAddressResponse], summary="更新设备地址关联")
async def update_device_address_endpoint(
		db: DbDep,
		_audit: AuditLogDep,
		id: int = Path(..., description="设备地址关联ID"),
		payload: DeviceAddressUpdate = Body(...),
		_: UserInDB = Depends(require_device_manage)
) -> ApiResponse[DeviceAddressResponse]:
	"""更新设备地址关联"""
	try:
		success = await update_device_address(db, id, payload)
		if not success:
			return ApiResponse.error("设备地址关联不存在", code=404)

		device_address = await get_device_address_by_id(db, id)
		return ApiResponse.success(DeviceAddressResponse.model_validate(device_address), "设备地址关联更新成功")
	except Exception as e:
		return ApiResponse.error(f"更新设备地址关联失败: {str(e)}", code=500)


@router.delete("/addresses/{id}", response_model=ApiResponse[DeviceOperationResult], summary="删除设备地址关联")
async def delete_device_address_endpoint(
		db: DbDep,
		_audit: AuditLogDep,
		id: int = Path(..., description="设备地址关联ID"),
		_: UserInDB = Depends(require_device_manage)
) -> ApiResponse[DeviceOperationResult]:
	"""删除设备地址关联"""
	try:
		success = await delete_device_address(db, id)
		if not success:
			return ApiResponse.error("设备地址关联不存在", code=404)

		result = DeviceOperationResult(
			success=True,
			message="设备地址关联删除成功"
		)
		return ApiResponse.success(result, "设备地址关联删除成功")
	except Exception as e:
		return ApiResponse.error(f"删除设备地址关联失败: {str(e)}", code=500)
